package com.wimcorp.magic.dataloader.client;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CellPanel;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.wimcorp.magic.data.AbilityData;
import com.wimcorp.magic.data.BehaviourData;
import com.wimcorp.magic.data.CostData;
import com.wimcorp.magic.dataloader.abilities.AbilityWidget;
import com.wimcorp.magic.dataloader.behaviors.BehaviorWidget;
import com.wimcorp.magic.dataloader.costs.CostWidget;
import com.wimcorp.magic.dataloader.costs.ManaCostWidget;
import com.wimcorp.magic.dataloader.costs.ReturnCostWidget;
import com.wimcorp.magic.dataloader.dto.CardDTO;
import com.wimcorp.magic.dataloader.dto.DeckDTO;
import com.wimcorp.magic.input.AbilityInput;
import com.wimcorp.magic.input.BehaviorInput;
import com.wimcorp.magic.input.CostInput;

public class DeckWidget extends Composite {

	private final DataServiceAsync dataService = GWT.create(DataService.class);

	private static final String CARD_IMAGE_PRE_FIX = "http://mtgimage.com/multiverseid/";
	private static final String CARD_IMAGE_POST_FIX = ".jpg";

	interface MyUiBinder extends UiBinder<Widget, DeckWidget> {
	}

	private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);

	@UiField
	ListBox listBox;

	@UiField
	HorizontalPanel content;

	@UiField
	VerticalPanel index;

	private Button saveCardButton = new Button("Save");
	private CheckBox verified = new CheckBox("Verified");

	private Image image = new Image();

	private VerticalPanel cardPanel = new VerticalPanel();

	private VerticalPanel behaviourPanel = new VerticalPanel();

	private VerticalPanel costPanel = new VerticalPanel();

	private VerticalPanel abilityPanel = new VerticalPanel();

	private TextArea cardDescription = new TextArea();
	private TextBox cardManaCost = new TextBox();

	private CardDTO currentCard;
	private Map<AbilityInput, AbilityWidget> abilityWidgets = new HashMap<>();
	private Map<BehaviorInput, BehaviorWidget> behaviorWidgets = new HashMap<>();
	private Map<CostInput, CostWidget> costWidgets = new HashMap<>();

	public DeckWidget() {

		initWidget(uiBinder.createAndBindUi(this));

		initDeckList();
		initBehaviorPanel();
		initAbilityPanel();
		initCostPanel();
		initSaveButton();
		initCardDescription();

		cardPanel.add(image);
		cardPanel.add(cardDescription);
		cardPanel.add(cardManaCost);
		cardPanel.add(costPanel);
		cardPanel.add(saveCardButton);
		cardPanel.add(verified);
		content.add(cardPanel);
		content.add(behaviourPanel);
		content.add(abilityPanel);

		cardPanel.setStylePrimaryName("card");
		behaviourPanel.setStylePrimaryName("behaviour");
		abilityPanel.setStylePrimaryName("behaviour");
		costPanel.setStylePrimaryName("behaviour");

	}

	private static CheckBox createCheckBox(String name, String label) {
		CheckBox checkBox = new CheckBox(label);
		checkBox.setName(name);
		return checkBox;
	}

	@UiHandler("listBox")
	void handleSelectDeck(ChangeEvent e) {
		String code = listBox.getValue(listBox.getSelectedIndex());
		dataService.getCards(code, new AsyncCallback<List<CardDTO>>() {

			@Override
			public void onFailure(Throwable caught) {
				caught.printStackTrace();
			}

			@Override
			public void onSuccess(List<CardDTO> result) {
				index.clear();
				boolean first = true;
				for (final CardDTO card : result) {
					Anchor anchor = new Anchor(card.getName());
					if (first) {

						loadCard(card);
						first = false;
					}
					if (card.isVerified()) {
						anchor.addStyleName("activeLink");
					}
					anchor.addClickHandler(new ClickHandler() {

						@Override
						public void onClick(ClickEvent event) {
							abilityWidgets = new HashMap<>();
							behaviorWidgets = new HashMap<>();
							costWidgets = new HashMap<>();
							loadCard(card);
							// ((Anchor)
							// event.getSource()).addStyleName("activeLink");
						}
					});
					index.add(anchor);
				}
			}
		});
	}

	private void loadCard(final CardDTO card) {
		verified.setValue(card.isVerified());
		loadImage(card.getMultiverseid());
		loadBehaviour(card);
		loadAbilities(card);
		loadCost(card);
		cardDescription.setText(card.getText());
		cardManaCost.setText(card.getManacost());
		currentCard = card;
	}

	private void loadImage(Long id) {
		image.setUrl(CARD_IMAGE_PRE_FIX + id + CARD_IMAGE_POST_FIX);
	}

	private void initDeckList() {
		dataService.getDeckNames(new AsyncCallback<List<DeckDTO>>() {
			@Override
			public void onFailure(Throwable caught) {
				caught.printStackTrace();
			}

			@Override
			public void onSuccess(List<DeckDTO> result) {
				for (DeckDTO deck : result) {
					listBox.addItem(deck.getName(), deck.getCode());
				}
				listBox.setSelectedIndex(32);
				handleSelectDeck(null);
			}
		});
	}

	private void initCardDescription() {
		cardDescription.setHeight("125px");
		cardDescription.setWidth("470px");

	}

	private void initBehaviorPanel() {
		behaviourPanel.add(new Label("Behaviour"));
		for (final BehaviorInput b : BehaviorInput.values()) {
			if (b != BehaviorInput.SUMMONING_SICKENSS && b != BehaviorInput.DEFAULT_ATTACK) {
				final VerticalPanel panel = new VerticalPanel();
				final CheckBox checkBox = createCheckBox(b.toString(), b.getName());
				panel.add(checkBox);
				checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
					@Override
					public void onValueChange(ValueChangeEvent<Boolean> event) {
						if (checkBox.getValue()) {
							// initBehaviorDescription(panel);
							BehaviorWidget behaviorWidget = behaviorWidgets.get(b);
							if (behaviorWidget == null) {
								behaviorWidget = BehaviorWidget.createBehaviorWidget(b);
								behaviorWidgets.put(b, behaviorWidget);
							}
							panel.add(behaviorWidget.getConfigurationPanel());

						} else {
							Widget w = panel.getWidget(0);
							panel.clear();
							panel.add(w);
						}
					}
				});
				behaviourPanel.add(panel);
			}
		}

	}

	private void initCostPanel() {
		costPanel.add(new Label("Costs"));
		costPanel.setStyleName("costPanel");
		for (final CostInput cost : CostInput.values()) {
			if (cost != CostInput.MANA_COST) {
				final VerticalPanel panel = new VerticalPanel();
				final CheckBox costCheckBox = createCheckBox(cost.toString(), cost.getName());
				panel.add(costCheckBox);
				costCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
					@Override
					public void onValueChange(ValueChangeEvent<Boolean> event) {
						if (costCheckBox.getValue()) {
							// initCostFields(panel, costCheckBox);
							CostWidget costWidget = costWidgets.get(cost);
							if (costWidget == null) {
								costWidget = CostWidget.createCostWidget(cost);
								costWidgets.put(cost, costWidget);
							}
							panel.add(costWidget.getConfigurationPanel());
						} else {
							Widget w = panel.getWidget(0);
							panel.clear();
							panel.add(w);
						}
					}
				});

				costPanel.add(panel);
			}
		}
	}

	private void initAbilityPanel() {
		abilityPanel.add(new Label("Abilities"));
		abilityPanel.setStyleName("abilityPanel");
		for (final AbilityInput ability : AbilityInput.values()) {
			final VerticalPanel panel = new VerticalPanel();
			final CheckBox abilityCheckBox = createCheckBox(ability.toString(), ability.getName());
			panel.add(abilityCheckBox);
			abilityCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
				@Override
				public void onValueChange(ValueChangeEvent<Boolean> event) {
					if (abilityCheckBox.getValue()) {
						AbilityWidget abilityWidget = abilityWidgets.get(ability);
						if (abilityWidget == null) {
							abilityWidget = AbilityWidget.createAbilityWidget(ability);
							abilityWidgets.put(ability, abilityWidget);
						}
						panel.add(abilityWidget.getConfigurationPanel());
					} else {
						Widget w = panel.getWidget(0);
						panel.clear();
						panel.add(w);
					}
				}
			});
			abilityPanel.add(panel);
		}
	}

	private void loadBehaviour(CardDTO card) {
		Set<BehaviourData> behaviours = card.getBehaviours();
		Iterator<Widget> resetIterator = behaviourPanel.iterator();
		while (resetIterator.hasNext()) {
			Widget next = resetIterator.next();
			if (next instanceof CellPanel) {
				next = ((CellPanel) next).getWidget(0);
				if (next instanceof CheckBox) {
					CheckBox c = (CheckBox) next;
					c.setValue(false);
					CellPanel parent = (CellPanel) c.getParent();
					parent.clear();
					parent.add(c);
				}
			}
		}
		for (BehaviourData behaviour : behaviours) {
			Iterator<Widget> loadBehaviourIterator = behaviourPanel.iterator();
			while (loadBehaviourIterator.hasNext()) {
				Widget next = loadBehaviourIterator.next();
				if (next instanceof CellPanel) {
					CellPanel panel = (CellPanel) next;
					next = panel.getWidget(0);
					if (next instanceof CheckBox) {
						CheckBox c = (CheckBox) next;
						if (behaviour.getBehaviour().equals(c.getName())) {
							c.setValue(true);
							/*
							 * initBehaviorDescription(panel); TextArea
							 * description = (TextArea) panel.getWidget(1);
							 * description.setText(behaviour.getDescription());
							 */

							BehaviorInput behaviorInput = BehaviorInput.valueOf(behaviour.getBehaviour());
							BehaviorWidget behaviorWidget = behaviorWidgets.get(behaviorInput);
							if (behaviorWidget == null) {
								behaviorWidget = BehaviorWidget.createBehaviorWidget(behaviorInput);
								behaviorWidgets.put(behaviorInput, behaviorWidget);
							}
							panel.add(behaviorWidget.getConfigurationPanel());
							behaviorWidget.load(behaviour);

						}
					}
				}
			}

		}

	}

	private void loadAbilities(CardDTO card) {
		Set<AbilityData> abilities = card.getAbilities();
		Iterator<Widget> resetIterator = abilityPanel.iterator();
		while (resetIterator.hasNext()) {
			Widget next = resetIterator.next();
			if (next instanceof CellPanel) {
				Widget checkBox = ((CellPanel) next).getWidget(0);
				if (checkBox instanceof CheckBox) {
					CheckBox c = (CheckBox) checkBox;
					c.setValue(false);
					CellPanel parent = (CellPanel) c.getParent();
					parent.clear();
					parent.add(c);
				}
			}

		}
		for (AbilityData ability : abilities) {
			Iterator<Widget> loadAbilityIterator = abilityPanel.iterator();
			while (loadAbilityIterator.hasNext()) {
				Widget next = loadAbilityIterator.next();
				if (next instanceof CellPanel) {
					CellPanel panel = (CellPanel) next;
					Widget checkBox = panel.getWidget(0);
					if (checkBox instanceof CheckBox) {
						CheckBox c = (CheckBox) checkBox;
						if (ability.getAbility().equals(c.getName())) {
							c.setValue(true);
							AbilityInput abilityInput = AbilityInput.valueOf(ability.getAbility());
							AbilityWidget abilityWidget = abilityWidgets.get(abilityInput);
							if (abilityWidget == null) {
								abilityWidget = AbilityWidget.createAbilityWidget(abilityInput);
								abilityWidgets.put(abilityInput, abilityWidget);
							}
							panel.add(abilityWidget.getConfigurationPanel());
							abilityWidget.load(ability);
						}
					}
				}
			}

		}

	}

	private void loadCost(CardDTO card) {
		Set<CostData> costs = card.getCosts();
		Iterator<Widget> resetIterator = costPanel.iterator();
		while (resetIterator.hasNext()) {
			Widget next = resetIterator.next();
			if (next instanceof CellPanel) {
				next = ((CellPanel) next).getWidget(0);
				if (next instanceof CheckBox) {
					CheckBox c = (CheckBox) next;
					c.setValue(false);
					CellPanel parent = (CellPanel) c.getParent();
					parent.clear();
					parent.add(c);
				}
			}
		}
		for (CostData cost : costs) {
			Iterator<Widget> loadCostIterator = costPanel.iterator();
			while (loadCostIterator.hasNext()) {
				Widget next = loadCostIterator.next();
				if (next instanceof CellPanel) {
					CellPanel panel = (CellPanel) next;
					next = panel.getWidget(0);
					if (next instanceof CheckBox) {
						CheckBox c = (CheckBox) next;
						if (cost.getCost().equals(c.getName())) {
							c.setValue(true);
							CostInput costInput = CostInput.valueOf(cost.getCost());
							CostWidget costWidget = costWidgets.get(costInput);
							if (costWidget == null) {
								costWidget = CostWidget.createCostWidget(costInput);
								costWidgets.put(costInput, costWidget);
							}
							panel.add(costWidget.getConfigurationPanel());
							costWidget.load(cost);
						}
					}
				}
			}

		}

	}

	private void initSaveButton() {
		saveCardButton.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				saveCard(currentCard);
			}

			private void saveCard(final CardDTO card) {
				card.setAbilities(getSelectedAbilities());
				card.setBehaviours(getSelectedBehaviours());
				card.setCosts(getSelectedCosts());
				card.setVerified(verified.isChecked());

				dataService.saveCard(card, new AsyncCallback<Void>() {
					@Override
					public void onFailure(Throwable caught) {
						Window.alert(caught.getMessage());
						caught.printStackTrace();
					}

					@Override
					public void onSuccess(Void result) {
						System.out.println("saved");

						Iterator<Widget> iterator = index.iterator();
						while (iterator.hasNext()) {
							Widget w = iterator.next();
							if (w instanceof Anchor) {
								Anchor anchor = (Anchor) w;
								if (anchor.getText().equals(card.getName())) {

									if (card.isVerified()) {
										anchor.addStyleName("activeLink");
									} else {
										anchor.removeStyleName("activeLink");
									}
								}
							}
						}

					}
				});
			}

			private Set<CostData> getSelectedCosts() {
				Set<CostData> costs = new HashSet<>();
				Iterator<Widget> iterator = costPanel.iterator();
				while (iterator.hasNext()) {
					Widget w = iterator.next();
					if (w instanceof CellPanel) {
						CellPanel panel = (CellPanel) w;
						w = panel.getWidget(0);
						if (w instanceof CheckBox) {
							CheckBox c = (CheckBox) w;
							if (c.getValue()) {
								CostWidget costWidget = costWidgets.get(CostInput.valueOf(((CheckBox) c).getName()));
								String config = costWidget.getConfig();

								costs.add(new CostData(costWidget.getName(), config));
							}
						}
					}
				}
				return costs;
			}

			private Set<BehaviourData> getSelectedBehaviours() {
				Set<BehaviourData> behaviours = new HashSet<>();
				Iterator<Widget> iterator = behaviourPanel.iterator();
				while (iterator.hasNext()) {
					Widget w = iterator.next();
					if (w instanceof CellPanel) {
						CellPanel panel = (CellPanel) w;
						w = panel.getWidget(0);
						if (w instanceof CheckBox) {
							CheckBox c = (CheckBox) w;
							if (c.getValue()) {
								/*
								 * BehaviourData behaviour = new
								 * BehaviourData(c.getName());
								 * behaviour.setDescription(((TextArea)
								 * panel.getWidget(1)).getText());
								 * behaviours.add(behaviour);
								 */

								BehaviorWidget behaviorWidget = behaviorWidgets.get(BehaviorInput
										.valueOf(((CheckBox) c).getName()));
								behaviours.add(new BehaviourData(behaviorWidget.getName(), behaviorWidget
										.getDescription()));

							}
						}
					}
				}
				return behaviours;
			}

			private Set<AbilityData> getSelectedAbilities() {
				Set<AbilityData> abilities = new HashSet<>();
				Iterator<Widget> iterator = abilityPanel.iterator();
				while (iterator.hasNext()) {
					Widget next = iterator.next();
					if (next instanceof CellPanel) {
						CellPanel cellPanel = (CellPanel) next;
						Widget checkBox = cellPanel.getWidget(0);
						if (checkBox instanceof CheckBox) {
							if (((CheckBox) checkBox).isChecked()) {
								AbilityWidget abilityWidget = abilityWidgets.get(AbilityInput
										.valueOf(((CheckBox) checkBox).getName()));
								abilities.add(new AbilityData(abilityWidget.getName(), abilityWidget.getAbilityConfig()
										.toString(), abilityWidget.getCosts()));
							}
						}
					}
				}
				return abilities;
			}

		});
	}

}
